package com.heatup.apt.common.util.Netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;

import java.util.concurrent.TimeUnit;

/**
 * 空闲连接以及超时
 *
 * 检测空闲连接和超时是为了及时释放资源。
 * 常见的方法发送消息用于测试一个不活跃的连接来,通常称为“心跳”,到远端来确定它是否还活着。
 * (一个更激进的方法是简单地断开那些指定的时间间隔的不活跃的连接)。
 *
 * 1. IdleStateHandler 将通过 IdleStateEvent 调用 userEventTriggered ，如果连接没有接收或发送数据超过60秒钟
 * 2. 心跳发送到远端
 * 3. 发送的心跳并添加一个侦听器，如果发送操作失败将关闭连接
 * 4. 事件不是一个 IdleStateEvent 的话，就将它传递给下一个处理程序
 * Created by blank on 2017/11/17 上午11:28
 */
public class IdleStateHandlerInitializer extends ChannelInitializer<Channel> {


    @Override
    protected void initChannel(Channel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new IdleStateHandler(0, 0, 60, TimeUnit.SECONDS)); //1
        pipeline.addLast(new HeartbeatHandler());


    }

    public static class HeartbeatHandler extends ChannelInboundHandlerAdapter {
        private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(
                Unpooled.copiedBuffer("HEARTBEAT", CharsetUtil.UTF_8));  //2

        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            if (evt instanceof IdleStateEvent) {
                ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate())
                        .addListener(ChannelFutureListener.CLOSE_ON_FAILURE); //3

            } else {
                super.userEventTriggered(ctx, evt);  //4
            }

        }
    }
}
